package com.kingbook.common.utils;

import com.kingbook.common.enums.JavaType;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 对象操作工具类, 继承org.apache.commons.lang3.ObjectUtils类
 */
public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {

	private static Logger logger = LoggerFactory.getLogger(ObjectUtils.class);
	
	/**
	 * 注解到对象复制，只复制能匹配上的方法。
	 * @param annotation
	 * @param object
	 */
	public static void annotationToObject(Object annotation, Object object){
		if (annotation != null){
			Class<?> annotationClass = annotation.getClass();
			Class<?> objectClass = object.getClass();
			for (Method m : objectClass.getMethods()){
				if (StringUtils.startsWith(m.getName(), "set")){
					try {
						String s = "get"+StringUtils.substring(m.getName(), 3);
						Object obj = annotationClass.getMethod(s).invoke(annotation);
						if (obj != null && !"".equals(obj.toString())){
							if (object == null){
								object = objectClass.newInstance();
							}
							m.invoke(object, obj);
						}
					} catch (Exception e) {
						// 忽略所有设置失败方法
					}
				}
			}
		}
	}

	/**
	 * 将VO转换成Map
	 * 
	 * @param obj
	 * @return
	 */
	public static Map<String, ?> serializeToMap(Object obj) {
		String methodName = "";
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		Map<String, Object> map = new HashMap<String, Object>();
		for (Field field : fields) {
			Method method = null; 
			try {
				methodName = "get"+Character.toUpperCase(field.getName().charAt(0))+field.getName().substring(1);
				method = clazz.getMethod(methodName, new Class[0]);
				if (method != null) {
					map.put(field.getName(), method.invoke(obj, new Object[0]));
				}
			} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
				logger.error(clazz.getName() + "." + field.getName() + "设置失败...", e);
			} catch (NoSuchMethodException | SecurityException e) {
				logger.error(clazz.getName() + "没有" + methodName + "方法或权限不够...", e);
			}
		}

		return map;
	}

	/**
	 * 将Map转换成VO
	 * 
	 * @return
	 */
	public static <T> T serializeToVo(Map<String, ?> map, Class<T> clazz) {
		T obj = null;
		String methodName = "";
		try {
			obj = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			logger.error(clazz.getName() + " 没有默认构造器...", e);
		}
		Method[] methods = clazz.getMethods();
		HashMap<String, Method> hm = new HashMap<String, Method>();
		for (Method method : methods) {
			methodName = method.getName();
			if (methodName.startsWith("set") && Modifier.isPublic(method.getModifiers())) {
				methodName = methodName.substring(3);
				hm.put(Character.toLowerCase(methodName.charAt(0)) + methodName.substring(1), method);
			}
		}

		for (String key : map.keySet()) {
			Method method = null; 
			try {
				method = hm.get(key);
				if (method != null) {
					method.invoke(obj, paresType(method, map.get(key)));
				}
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
				logger.error(clazz.getName() + "." + method.getName() + "设置失败...", e);
			}
		}
		return obj;
	}

	/**
	 * 序列化对象
	 * @param object
	 * @return
	 */
	public static byte[] serializeToBytes(Object object) {
		ObjectOutputStream oos = null;
		ByteArrayOutputStream baos = null;
		try {
			if (object != null){
				baos = new ByteArrayOutputStream();
				oos = new ObjectOutputStream(baos);
				oos.writeObject(object);
				return baos.toByteArray();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 反序列化对象
	 * @param bytes
	 * @return
	 */
	public static Object serializeToObject(byte[] bytes) {
		ByteArrayInputStream bais = null;
		try {
			if (bytes != null && bytes.length > 0){
				bais = new ByteArrayInputStream(bytes);
				ObjectInputStream ois = new ObjectInputStream(bais);
				return ois.readObject();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	
	@SuppressWarnings("rawtypes")
	private static Object paresType(Method method, Object value) {
		Class[] cs = method.getParameterTypes();
		if (cs != null && cs.length == 1 && value != null) {
			String type = cs[0].getName();
			try {
				if (JavaType.STRING.equals(type))
					return value instanceof String ? value : value.toString();
				else if (JavaType.INTEGER.equals(type))
					return value instanceof Integer ? value : Integer.valueOf(value.toString());
				else if (JavaType.LONG.equals(type))
					return value instanceof Long ? value : Long.valueOf(value.toString());
				else if (JavaType.FLOAT.equals(type))
					return value instanceof Float ? value : Float.valueOf(value.toString());
				else if (JavaType.DOUBLE.equals(type))
					return value instanceof Double ? value : Double.valueOf(value.toString());
				else if (JavaType.BIGDECIMAL.equals(type))
					return value instanceof BigDecimal ? value : new BigDecimal(value.toString());
				else if (JavaType.DATE.equals(type))
					return value instanceof Date ? value : DateUtils.parse(value.toString());
				else if (JavaType.TIMESTAMP.equals(type))
					return value instanceof Timestamp ? value : DateUtils.parseTimestamp(value.toString());
				else if (JavaType.BOOLEAN.equals(type))
					return value instanceof Boolean ? value : Boolean.valueOf(value.toString());
				else
					return value;
			} catch (ParseException e) {
				logger.error(method.getName() + "(" + type + ") 参数解析错误 ");
			}
		}
		return null;
	}

}
